/*******************************************************************************
 * @file Copyright 2009 The CREATE Lab at CMU
 * 
 *       This file is part of JubJub, an open source project.
 *       http://code.google.com/p/jubjub/
 * 
 *       Redistribution and use in source and binary forms, with or without
 *       modification, are permitted provided that the following conditions are
 *       met:
 * 
 *       Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 * 
 *       Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 *       Neither the name of Carnegie Mellon nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 * 
 *       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *       HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *       LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *       OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

package edu.cmu.ri.createlab.jj.projects;

import java.util.LinkedList;

import javax.swing.JFrame;

import edu.cmu.ri.createlab.jj.blocks.*;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.AccessTypes;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.ExpressTypes;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.FlowTypes;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.VarTypes;
import edu.cmu.ri.createlab.jj.ui.JJDemoPanel;
import edu.cmu.ri.createlab.jj.visitors.BVJavaWriter;

public class JJDemoProject
{
   public static JJProject getDemoProject()
   {
      JJProject demoP = new JJProject("FinchDemo");
      JJClass finchDemo;
      CodeBlock main, sleep;
      BlockBlock dance;
      VarBlock i, j, lDist, rDist, lSpeed, rSpeed, turnDeg, lit, intDefault, boolDefault;
      ObjectBlock myFinch;
      VarBlock tempVar;
      FlowBlock whileDefault, ifelseDefault;
      FlowBlock tempFlow;
      ExpressionBlock assign, add, sub, grt, lt, mult, div, equal;
      ExpressionBlock tempExp;
      CodeBlock driveStraight, setVel, setLED, turn, stop, newFinch, quit;
      CommentBlock comment;
      JJTab javaTab, finchTab;
      JJSubTab numbersST, flowST, moveST, otherFST, otherST;
      
      RefBlock tempRef, tr2, tr3;
      
      try
      {
         finchDemo = new JJClass("FinchDemo");
         demoP.addClass(finchDemo);
         
         //Vars
         i = new VarBlock("i", null, 0, VarTypes.INT);
         j = new VarBlock("j", null, 1, VarTypes.INT);
         lDist = new VarBlock("dist1", null, 2, VarTypes.INT);
         lDist.setValue("10", 0);
         rDist = new VarBlock("dist2", null, 3, VarTypes.INT);
         rDist.setValue("10", 0);
         lSpeed = new VarBlock("speed1", null, 4, VarTypes.INT);
         lSpeed.setValue("10", 0);
         rSpeed = new VarBlock("speed2", null, 5, VarTypes.INT);
         rSpeed.setValue("10", 0);
         turnDeg = new VarBlock("turnDeg", null, 6, VarTypes.INT);
         turnDeg.setValue("90", 0);
         lit = new VarBlock("literal", null, 7, VarTypes.INT, true);

         intDefault = new VarBlock("intDef", null, 8, VarTypes.INT);
         boolDefault = new VarBlock("boolDef", null, 9, VarTypes.BOOLEAN);
         
         myFinch = new ObjectBlock("myFinch", null, 0, 0, null);
         myFinch.setObjectType("Finch");
         
         comment = new CommentBlock("comment", null, 0);
         
         //Exps
         assign = new ExpressionBlock(null, 10, ExpressTypes.ASSIGN, "=");
         add = new ExpressionBlock(null, 11, ExpressTypes.ARITH, "+");
         sub = new ExpressionBlock(null, 12, ExpressTypes.ARITH, "-");
         mult = new ExpressionBlock(null, 11, ExpressTypes.ARITH, "*");
         div = new ExpressionBlock(null, 11, ExpressTypes.ARITH, "/");
         grt = new ExpressionBlock(null, 13, ExpressTypes.LOGIC, ">");
         lt = new ExpressionBlock(null, 13, ExpressTypes.LOGIC, "<");
         equal = new ExpressionBlock(null, 13, ExpressTypes.LOGIC, "==");
         
         //Flow
         LinkedList<TaggedCodePiece> tcp = new LinkedList<TaggedCodePiece>();
         tcp.add(new TaggedCodePiece("while("));
         tcp.add(new TaggedCodePiece("exp", 0));
         tcp.add(new TaggedCodePiece(")"));
         
         whileDefault = new FlowBlock("while", null, 14);
         whileDefault.setCode(tcp, 0);
         whileDefault.addParam(boolDefault.clone(9), 0);
         
         tcp = new LinkedList<TaggedCodePiece>();
         tcp.add(new TaggedCodePiece("if("));
         tcp.add(new TaggedCodePiece("exp", 0));
         tcp.add(new TaggedCodePiece(")"));
         
         ifelseDefault = new FlowBlock("ifelse", null, 14);
         ifelseDefault.setFType(FlowTypes.IFELSE);
         ifelseDefault.setCode(tcp, 0);
         ifelseDefault.addParam(boolDefault.clone(9), 0);
         
         tcp = new LinkedList<TaggedCodePiece>();
         tcp.add(new TaggedCodePiece("else"));
         
         ifelseDefault.setCode(tcp, 2);
         
         //Code calls
         AccessTypes[] acc = {AccessTypes.PUBLIC, AccessTypes.STATIC};
         
         tcp = new LinkedList<TaggedCodePiece>();
         tcp.add(new TaggedCodePiece("try{Thread.sleep("));
         tcp.add(new TaggedCodePiece("milis", 0));
         tcp.add(new TaggedCodePiece(");}catch(Exception e){}"));
         
         sleep = new CodeBlock("sleep", null, 2, null, null, null);
         tempVar = intDefault.clone(0);
         tempVar.setName("milis");
         sleep.addParam(tempVar);
         sleep.setTaggedCode(tcp);
         sleep.setAccess(acc);
         sleep.setComment("Causes the program to delay for the specified number of miliseconds.");
         
         driveStraight = new CodeBlock("straight", null, 2, null, null, null);
         tempVar = intDefault.clone(0);
         tempVar.setName("distance");
         driveStraight.addParam(tempVar);
         tempVar = intDefault.clone(0);
         tempVar.setName("speed");
         driveStraight.addParam(tempVar);
         driveStraight.setComment("Causes the Finch to drive forward a set distance and speed. Speed ranges from 1 to 35.");
         
         turn = new CodeBlock("turn", null, 2, null, null, null);
         tempVar = intDefault.clone(0);
         tempVar.setName("degrees");
         turn.addParam(tempVar);
         tempVar = intDefault.clone(0);
         tempVar.setName("speed");
         turn.addParam(tempVar);
         turn.setComment("Causes the Finch to turn in place a set amount and speed. Speed ranges from 1 to 35.");
         
         setVel = new CodeBlock("setWheelVelocities", null, 2, null, null, null);
         tempVar = intDefault.clone(0);
         tempVar.setName("leftVelocity");
         setVel.addParam(tempVar);
         tempVar = intDefault.clone(0);
         tempVar.setName("rightVelocity");
         setVel.addParam(tempVar);
         setVel.setComment("Sets the velocities for the left and right wheels. Velocity ranges from -35 to 35.");
          
         setLED = new CodeBlock("setLED", null, 2, null, null, null);
         tempVar = intDefault.clone(0);
         tempVar.setName("red");
         setLED.addParam(tempVar);
         tempVar = intDefault.clone(0);
         tempVar.setName("green");
         setLED.addParam(tempVar);
         tempVar = intDefault.clone(0);
         tempVar.setName("blue");
         setLED.addParam(tempVar);
         setLED.setComment("Sets the color of the Finche's nose given an RGB value. Values range from 0 to 255.");
         
         stop = new CodeBlock("stopWheels", null, 2, null, null, null);
         stop.setComment("Stops the Finch's wheels.");
         
         quit = new CodeBlock("quit", null, 2, null, null, null);
         quit.setComment("Disconnects from the Finch.");
         
         AccessTypes[] pubAcc = {AccessTypes.PUBLIC};
         newFinch = new CodeBlock("Finch", null, 2, null, null, null);
         newFinch.setAccess(pubAcc);
         newFinch.setConstructor(true);
         
         //Main method
         tcp = new LinkedList<TaggedCodePiece>();
         tcp.add(new TaggedCodePiece("dance();\n      System.exit(0);"));
         
         main = new CodeBlock("main", finchDemo, 0);
         main.setAccess(acc);
         tempVar = new VarBlock("args", null, 0, VarTypes.OBJECT);
         tempVar.setObjectType("String[]");
         main.addParam(tempVar);
         main.setTaggedCode(tcp);
         finchDemo.addMethodBlock(main);
         
         //Demo BlockBlock
         dance = new BlockBlock("dance", finchDemo, 0);
         dance.setComment("Makes the Finch do a dance.");
         dance.setAccess(acc);
         dance.addVar(i);
         dance.addVar(j);
         dance.addVar(lDist);
         dance.addVar(rDist);
         dance.addVar(lSpeed);
         dance.addVar(rSpeed);
         dance.addVar(turnDeg);
         dance.addVar(myFinch.getVariable());
         tempRef = new RefBlock(0,myFinch);
         tempRef.addParam(new RefBlock(0, newFinch));
         dance.addCode(tempRef);
         tempRef = new RefBlock(0,whileDefault);
         tempRef.setIndex(0);
         tr2 = new RefBlock(0, grt.clone(0));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("3", 0);
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("10", 0);
         tr2.addParam(new RefBlock(0, i));
         tempRef.addParam(tr2);
         dance.addCode(tempRef);
         tempRef = new RefBlock(0, driveStraight);
         tempRef.addParam(new RefBlock(0,rDist));
         tempRef.addParam(new RefBlock(0,rSpeed));
         tr2 = new RefBlock(0, myFinch);
         tr2.addParam(tempRef);
         dance.addCode(tr2);
         tempRef = new RefBlock(0, turn);
         tempRef.addParam(new RefBlock(0,turnDeg));
         tempRef.addParam(new RefBlock(0,lSpeed));
         tr2 = new RefBlock(0, myFinch);
         tr2.addParam(tempRef);
         dance.addCode(tr2);
         tempRef = new RefBlock(0,myFinch);
         tempRef.addParam(new RefBlock(0,stop));
         dance.addCode(tempRef);
         tempRef = new RefBlock(0, assign);
         tr2 = new RefBlock(0,add);
         tr2.addParam(new RefBlock(0, i));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(1).getBlock()).setValue("2", 0);
         tempRef.addParam(new RefBlock(0,i));
         tempRef.addParam(tr2);
         dance.addCode(tempRef);
         tempRef = new RefBlock(0,whileDefault);
         tempRef.setIndex(3);
         dance.addCode(tempRef);
         tempRef = new RefBlock(0,myFinch);
         tr2 = new RefBlock(0,quit);
         tempRef.addParam(tr2);
         dance.addCode(tempRef);
         
         //Demo tabs
         javaTab = new JJTab("basic");
         finchTab = new JJTab("myFinch");
         numbersST = new JJSubTab("Numbers");
         flowST = new JJSubTab("Flow");
         moveST = new JJSubTab("Movement");
         otherST = new JJSubTab("Other");
         otherFST = new JJSubTab("Other");
         
         //literal block
         tempRef = new RefBlock(0, lit.clone(0));
         numbersST.addBlock(tempRef);
         //Logic and Arith expressions
         tempRef = new RefBlock(0, add);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, sub);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, mult);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, div);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, grt);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, lt);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         tempRef = new RefBlock(0, equal);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         numbersST.addBlock(tempRef);
         //assignment
         tempRef = new RefBlock(0, assign);
         tempRef.addParam(new RefBlock(0, lit.clone(0)));
         tr2 = new RefBlock(0, add);
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tempRef.addParam(tr2);
         numbersST.addBlock(tempRef);
         
         //Flow subtab with while block
         tempRef = new RefBlock(0, whileDefault);
         tempRef.setIndex(0);
         tr2 = new RefBlock(0, grt);
         tr2.addParam(new RefBlock(0,lit.clone(0)));
         tr2.addParam(new RefBlock(0,lit.clone(0)));
         tempRef.addParam(tr2);
         flowST.addBlock(tempRef);
         tempRef = new RefBlock(0, whileDefault);
         tempRef.setIndex(3);
         flowST.addBlock(tempRef);

         tempRef = new RefBlock(0, ifelseDefault);
         tempRef.setIndex(0);
         tempRef.setName("if");
         tr2 = new RefBlock(0, grt);
         tr2.addParam(new RefBlock(0,lit.clone(0)));
         tr2.addParam(new RefBlock(0,lit.clone(0)));
         tempRef.addParam(tr2);
         flowST.addBlock(tempRef);
         tempRef = new RefBlock(0, ifelseDefault);
         tempRef.setName("   else");
         tempRef.setIndex(2);
         flowST.addBlock(tempRef);
         tempRef = new RefBlock(0, ifelseDefault);
         tempRef.setIndex(3);
         flowST.addBlock(tempRef);
         
         tempRef = new RefBlock(0, sleep);
         tr2 = new RefBlock(0,lit.clone(0));
         ((VarBlock)tr2.getBlock()).setValue("millis", 0);
         tempRef.addParam(tr2);
         flowST.addBlock(tempRef);
         
         //Finch movement subtab
         //drive
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, driveStraight);
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("distance", 0);
         ((VarBlock)tr2.getParams().get(1).getBlock()).setValue("speed", 0);
         tempRef.addParam(tr2);
         moveST.addBlock(tempRef);
         //turn
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, turn);
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("degrees", 0);
         ((VarBlock)tr2.getParams().get(1).getBlock()).setValue("speed", 0);
         tempRef.addParam(tr2);
         moveST.addBlock(tempRef);
         //set wheel velocities
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, setVel);
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("leftVelocity", 0);
         ((VarBlock)tr2.getParams().get(1).getBlock()).setValue("rightVelocity", 0);
         tempRef.addParam(tr2);
         moveST.addBlock(tempRef);
         //stop
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, stop);
         tempRef.addParam(tr2);
         moveST.addBlock(tempRef);
         
         //set LED color
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, setLED);
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         tr2.addParam(new RefBlock(0, lit.clone(0)));
         ((VarBlock)tr2.getParams().get(0).getBlock()).setValue("red", 0);
         ((VarBlock)tr2.getParams().get(1).getBlock()).setValue("green", 0);
         ((VarBlock)tr2.getParams().get(2).getBlock()).setValue("blue", 0);
         tempRef.addParam(tr2);
         otherFST.addBlock(tempRef);
         //new finch
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, newFinch);
         tempRef.addParam(tr2);
         otherFST.addBlock(tempRef);
         //quit
         tempRef = new RefBlock(0, myFinch);
         tr2 = new RefBlock(0, quit);
         tempRef.addParam(tr2);
         otherFST.addBlock(tempRef);
         
         tempRef = new RefBlock(0, comment);
         otherST.addBlock(tempRef);
         
         javaTab.addSubTab(numbersST);
         javaTab.addSubTab(flowST);
         javaTab.addSubTab(otherST);
         finchTab.addSubTab(moveST);
         finchTab.addSubTab(otherFST);
         
         
         demoP.addTab(javaTab);
         demoP.addTab(finchTab);
         finchDemo.addMethodBlock(sleep);
         finchDemo.addMethodBlock(dance);
         //finchDemo.addImport("Finch");
         finchDemo.addImport("finch.*");
         
      }
      catch(Exception e)
      {
         System.out.println(e.getMessage());
      }
      
      return demoP;
   }
   
   public static void main(String[] args)
   {
      JJDemoPanel demoJJ = new JJDemoPanel();
      JJProject demoProj = getDemoProject();//JJProject.getTestProject();
//      BVJavaWriter write = new BVJavaWriter();
      
//      demoProj.accept(write);
//      write.setWrite(true, false);
//      write.finish();
      
      demoJJ.setProject(demoProj);
      demoJJ.addTab(demoProj.getTabs().get(0));
      demoJJ.addTab(demoProj.getTabs().get(1));
      //demoJJ.setTab(demoProj.getTabs().get(0));
      demoJJ.setCurrBlock((BlockBlock)(demoProj.getClasses().get(0).getMethodBlocks().get(2)));
            
      JFrame frame = new JFrame("JubJub Demo");
      
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(demoJJ);
      
      frame.pack();
      
      frame.setVisible(true);
   }
}
